package net.gdface.sdk.fse;

import java.nio.LongBuffer;
import java.util.Arrays;
import java.util.Comparator;

import net.gdface.sdk.FseResult;
import net.gdface.utils.BufferUtils;
import net.gdface.utils.BinaryUtils;

/**
 * 特征码内存对象<br>
 * 特征码内存JNI内存对象的Java层映射,
 * 该类实现了{@link Comparable}接口，可以根据相似度结果字段({@link CodeBean#similarity})排序
 * @author guyadong
 *
 */
public  class CodeBean implements Comparable<CodeBean>{	
	/**
	 * 特征码ID,
	 * 特征码的MD5校验值(使用MD5保证特征码ID的唯一性)
	 */
	public	byte[] id=null;
	/**
	 * 人脸特征码(人脸模板)数据，数据长度与实际应用的算法相关
	 */
	public byte[] code=null;
	/**
	 * 当前特征码所属的图像的MD5校验值(图像ID),可为{@code null},
	 * 应用层也可将此字段根据业务需要解释为其他含义
	 */
	public String imgMD5=null;
	/**
	 * 相似度比较结果，该字段只在特征码搜索方法返回值中有效。用于当前存储人脸特征方法调用搜索返回结果.
	 * 代表当前特征码与输入搜索人脸特征的相似度比较值。
	 */
	public double similarity=0;
	
	public CodeBean() {
	}
	public CodeBean(byte[] id, byte[] code, String imgMD5, Double similarity) {
		this.id = id;
		this.code = code;
		this.imgMD5 = imgMD5;
		if(similarity != null){
			this.similarity = similarity;
		}
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + Arrays.hashCode(code);
		result = prime * result + Arrays.hashCode(id);
		result = prime * result + ((imgMD5 == null) ? 0 : imgMD5.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof CodeBean))
			return false;
		CodeBean other = (CodeBean) obj;
		if (!Arrays.equals(code, other.code))
			return false;
		if (!Arrays.equals(id, other.id))
			return false;
		if (imgMD5 == null) {
			if (other.imgMD5 != null)
				return false;
		} else if (!imgMD5.equals(other.imgMD5))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return toString(false);
	}
	public String toString(boolean full) {
		String out=String.format("id=[%s],imgMD5=[%s],similarity=%f", BinaryUtils.toHex(id),imgMD5,similarity);
		if(full){
			out+=String.format("\ncode:\n%s\n", null==code?"null":BinaryUtils.toHex(code));
		}
		return out;
	}
	@Override
	public int compareTo(CodeBean o) {
		double sub = similarity - o.similarity;
		return sub > 0 ? 1 : (sub < 0 ? -1 : 0);
	}

	/**
	 * 将{@link #imgMD5}转为应用id(Long),如果{@link #imgMD5}为{@code null}则返回{@code null}
	 * @return
	 */
	public Long appLongId(){
		return asAppID(imgMD5);
	}
	/**
	 * 将{@link #imgMD5}转为应用id(Integer),如果{@link #imgMD5}为{@code null}则返回{@code null}
	 * @return
	 */
	public Integer appIntId(){
		Long l = asAppID(imgMD5);
		return l == null ? null : l.intValue();
	}
	/**
	 * 用于相似度排序的{@link Comparator}实例
	 */
	public static final Comparator<CodeBean> COMPARATOR = new Comparator<CodeBean>() {
		@Override
		public int compare(CodeBean o1, CodeBean o2) {
			return o1.compareTo(o2);
		}
	};
	/**
	 * 将Long类型整数转为32位的字符串,用于 {@link #imgMD5}字段
	 * @param appid
	 * @return appid为{@code null}则返回{@code null}
	 */
	public static String asImgMD5(long appid){
		LongBuffer buffer = LongBuffer.allocate(2).put(0).put(appid);
		return BinaryUtils.toHex(BufferUtils.asByteArray(buffer.array()));
	}
	/**
	 * 从{@link #imgMD5}字段返回Long类型整数,
	 * @param imgMD5 HEX格式(32字节长)的MD5
	 * @return imgMD5为{@code null}则返回{@code null}
	 */
	public static Long asAppID(String imgMD5){
		if(imgMD5 != null && imgMD5.getBytes().length == 32){			
			return BufferUtils.asLongArray(BinaryUtils.hex2Bytes(imgMD5))[1];
		}
		return null;
	}
	public byte[] getId() {
		return id;
	}
	public void setId(byte[] id) {
		this.id = id;
	}
	public byte[] getCode() {
		return code;
	}
	public void setCode(byte[] code) {
		this.code = code;
	}
	public String getImgMD5() {
		return imgMD5;
	}
	public void setImgMD5(String imgMD5) {
		this.imgMD5 = imgMD5;
	}
	public double getSimilarity() {
		return similarity;
	}
	public void setSimilarity(double similarity) {
		this.similarity = similarity;
	}
	public static final FseResult[] toFseResult(CodeBean[] codeBeans){
		if(codeBeans != null){
			FseResult[] result = new FseResult[codeBeans.length];
			for(int i =0;i<result.length;++i){
				result[i] = new FseResult(codeBeans[i].id, codeBeans[i].imgMD5, codeBeans[i].similarity);
			}
			return result;
		}
		return null;
	}
}